package locality;

import java.util.ArrayList;

import mantel.mantelTest;

import tool.*;

import genome.*;

public class distanceMapGenerator {
	public ReverseHashTable<Genotype,ArrayList<Double>> genotypeToPhenotype = new ReverseHashTable<Genotype,ArrayList<Double>>();
	public ReverseHashTable<ArrayList<Double>,Genotype> phenotypeToGenotype = new ReverseHashTable<ArrayList<Double>,Genotype>();
	
	
	public distanceMapGenerator(ArrayList<Genotype> space, int PROBLEM_CASE){
		populateHashTable(space,PROBLEM_CASE);
	}
	
	public static void main(String args[]){
		
	}
	
	public void populateHashTable(ArrayList<Genotype> space, int PROBLEM_CASE){
		
		//Obtains the genotype space for input genotype, then generates the corresponding phenotype for each member and adds both to the hashtable
		
		switch(PROBLEM_CASE){
			case 0: //symbolic value phenotype
				CoSymbolicRegression csr = new CoSymbolicRegression(space.get(0), space.get(0));
				for(Genotype individual:space){
					ArrayList<Double> phenotype = new ArrayList<Double>();
					double[] x = csr.symbolicValues(individual);
					for(int i=0;i<x.length;i++){
						phenotype.add(x[i]);
					}
					genotypeToPhenotype.put(individual,phenotype);
				}
			break;
			
			case 1: //vector phenotype
				for(Genotype individual:space){
					ArrayList<Double> phenotype = new ArrayList<Double>();
					double[] x = individual.toVector();
					for(int i=0;i<x.length;i++){
						phenotype.add(x[i]);
					}
					genotypeToPhenotype.put(individual,phenotype);
				}
			break;
			
			case 2: //symbolic regression phenotype
				double[] range = {0.0,2.0};
				
				for(Genotype individual:space){
					ArrayList<Double> phenotype = new ArrayList<Double>();
					double f = individual.quickSymbolicRegression(8, range);
					phenotype.add(f);
					genotypeToPhenotype.put(individual,phenotype);
				}
		}
		
		
		
		phenotypeToGenotype = genotypeToPhenotype.getInverse(); //also create inverse map
	}
	
	public ArrayList<double[][]> genDMatrix(){
		//naive approach first - maybe include distance matrix class for more efficient routines later
		
		System.out.println("Generating distance matrix...");
		
		ArrayList<double[][]> dmatrices = new ArrayList<double[][]>();
		
		int x = genotypeToPhenotype.size();
		double[][] GDIFF = new double[x][x];
		double[][] PDIFF = new double[x][x];
		
		ArrayList<Genotype> gspace = new ArrayList<Genotype>(genotypeToPhenotype.keySet());
		int i=0; int j=0;
		for(Genotype g1:gspace){
			for(Genotype g2:gspace){
				//GDIFF[i][j] = g1.distanceTo(g2);
				GDIFF[i][j] = g1.diff(g2);
				ArrayList<Double> p1 = genotypeToPhenotype.get(g1);
				ArrayList<Double> p2 = genotypeToPhenotype.get(g2);
				PDIFF[i][j] = euclid(p1,p2);
				j = j+1;
			}
			j = 0;
			i = i+1;
		}
		dmatrices.add(GDIFF); dmatrices.add(PDIFF);
		return dmatrices;
	}
	
	public static double euclid(ArrayList<Double> i1, ArrayList<Double> i2){
		//returns the euclidean distance between two double arrays
		double e2 = 0.0;
		for(Double x1:i1){
			for(Double x2:i2){
				e2 = e2+ Math.pow((x2-x1),2);
			}
		}
		return Utility.roundToSignificantFigures(Math.sqrt(e2),5);
	}
	
}
